# -*- coding: utf-8 -*-
# @Time    : 2020/1/8 11:05
# @Author  : ZSQ
# @Email   : zsq199270918@163.com
# @FileName: digit_to_rmb.py
# @Software: PyCharm
import re


class DigitToRmb(object):
    def __init__(self, num: int or float = 0.0):
        self.num = num
        # 数字与中文 字典
        self.cn_dict = {0: u'零', 1: u'壹', 2: u'贰', 3: u'叁', 4: u'肆', 5: u'伍', 6: u'陆', 7: u'柒', 8: u'捌', 9: u'玖'}
        # 单位字典
        self.unit_dict = {1: u'元', 2: u'万', 3: u'亿', 4: u'万亿'}
        # 单位字典(每4位)
        self.step_dict = dict(zip([1, 2, 3, 4, ], [u'', u'拾', u'佰', u'仟']))

    def deal_integer(self, _integer):
        """
        处理整数位
        :param _num: str
        :return: str
        """
        # 将整数部分按[万亿，亿，万，'']单位拆分
        _int_li = self.split_integer(_integer)
        # 对整数部分进行转换
        _int_chk = self.change_int_to_rmb(_int_li)
        return _int_chk

    def deal_decimal(self, _decimal):
        """
        处理小数位
        :param _num: str
        :return: str
        """
        chk = u''
        if _decimal and int(_decimal):
            _decimal_len = len(_decimal)
            # 两位小数
            if _decimal_len == 2:
                # 第一位为0
                if _decimal.startswith('0'):
                    chk += (u'零角' + self.cn_dict[int(_decimal[1])] + u'分')
                # 第二位为0
                elif _decimal.endswith('0'):
                    chk += self.cn_dict[int(_decimal[0])] + u'角整'
                # 都不为0
                else:
                    chk += (self.cn_dict[int(_decimal[0])] + u'角' + self.cn_dict[int(_decimal[1])] + u'分')
            # 一位小数
            else:
                chk += self.cn_dict[int(_decimal[0])] + u'角整'
        return chk

    @staticmethod
    def split_integer(_integer):
        """
        将整数字符串拆分成[万亿，亿，万，'']的list
        :param _integer: str
        :return: list
        """
        _integer_li = []
        # 去除首位为0的干扰 比如00100
        _integer = str(int(_integer))
        # 取商和余数   num_y=len(_integer)%4   num_z=len(_integer)//4
        num_z, num_y = divmod(len(_integer), 4)
        # 对每4位进行切分
        if num_y:
            _integer_li.append(_integer[0:num_y])  # 不足4位，优先切分
        flag = 0
        while flag < num_z:
            start = num_y + 4 * flag
            end = num_y + 4 * (flag + 1)
            _integer_li.append(_integer[start:end])
            flag += 1
        return _integer_li

    def change_int_to_rmb(self, _int_li):
        """
        将整数转换成中文RMB
        :param _integer_li: list  [万亿，亿，万，'']
        :return: str
        """
        chk = u''
        _int_len = len(_int_li)
        # 遍历，对每部分进行转换
        for i, _int_str in enumerate(_int_li):
            # 不全部为0
            if int(_int_str):
                # [万亿，亿，万] 末尾为0时，转换后需在末尾添加 '零'
                if _int_str.endswith('0') and i < _int_len - 1:
                    chk += (self.change_integer(_int_str) + self.unit_dict[_int_len - i] + u'零')
                else:
                    chk += (self.change_integer(_int_str) + self.unit_dict[_int_len - i])
            # 全部为0
            else:
                chk += u'零'
        # 正则处理连续两个及以上 '零' 的情况
        regex = re.compile(u'零{2,}')
        chk = regex.sub(u'零', chk)
        return chk

    def change_integer(self, _integer):
        """
        对[万亿，亿，万，'']的list中每个字符串分组进行大写化再合并
        :param _integer: str
        :return: str
        """
        _integer_len = len(_integer)
        chk = u''
        # 遍历，对每一位进行转换
        for i in range(_integer_len):
            # 为0的情况
            if int(_integer[i]) == 0:
                # 对于 非末尾且后一位不为0 的情况设置为0，比如:1201
                if i < _integer_len - 1 and int(_integer[i + 1]) != 0:
                    chk += self.cn_dict[0]
            # 不为0的情况
            else:
                chk += (self.cn_dict[int(_integer[i])] + self.step_dict[_integer_len - i])
        return chk

    def num_split(self, _num):
        """
        拆分为整数和小数
        :param _num: 数字/数字字符串
        :return: (str1,str2)
        """
        ret_li = str(_num).split('.')
        # 有小数
        if len(ret_li) == 2:
            ret_1 = ret_li[0]
            ret_2 = ret_li[1]
        # 无小数
        else:
            ret_1 = ret_li[0]
            ret_2 = None
        return ret_1, ret_2

    def check_num(self, _num):
        """
        对需要转换的 数字/数字字符串 进行校验
        :param _num: 数字/数字字符串
        :return: bool
        """
        try:
            # 转为字符串
            num_str = str(_num)
            # 去空白
            num_str = num_str.replace(' ', '')
            # 最多只有一个小数点
            assert num_str.count('.') <= 1
            # 按小数点切分
            num_li = num_str.split('.')
            # 有小数点
            if num_str.count('.') == 1:
                # 小数点后最多两位
                assert len(num_li[1]) <= 2
            # 最多16位整数
            assert len(str(int(num_li[0]))) <= 16
            num_str = num_str.replace('.', '')
            # 去掉小数点也能转换为int
            int(num_str)
        except:
            return False
        else:
            return True

    @staticmethod
    def merge_int_and_decimal(_integer_chk, _decimal_chk):
        """
        合并整数部分和小数部分
        :param _integer: str  整数部分
        :param _decimal: str  小数部分
        :return: str
        """
        # 去掉 '零' 的干扰
        _integer = _integer_chk.replace('零', '')
        # 整数+小数
        if _integer and _decimal_chk:
            return _integer_chk + _decimal_chk
        # 整数
        elif _integer and not _decimal_chk:
            return _integer_chk
        # 小数
        elif not _integer and _decimal_chk:
            _decimal_chk = _decimal_chk.replace(u'零角', u'')
            return _decimal_chk
        else:
            return u'零元'

    def main(self):
        """
        主函数
        :return: str  '陆拾万壹仟叁佰零玖元'
        """
        # 校验需要转换的数字/字符串
        if self.check_num(self.num):
            # 拆分为整数部分和小数部分
            _integer, _decimal = self.num_split(self.num)
            # 转换整数部分
            _int_chk = self.deal_integer(_integer)
            # 转换小数部分
            _decimal_chk = self.deal_decimal(_decimal)
            # 合并整数和小数
            chk = self.merge_int_and_decimal(_int_chk, _decimal_chk)
            return chk
        else:
            print('>>>输入有误<<<\n>>>只支持 数字/数字字符串<<<\n>>>整数最多16位，小数点后最多两位<<<')


if __name__ == '__main__':
    dtb = DigitToRmb(num=0.01)
    print(dtb.main())
